/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

package scheduler;

import commands.GameCommand;
import java.util.ArrayDeque;
import java.util.concurrent.CopyOnWriteArrayList;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.atomic.AtomicBoolean;

/**
 *
 * @author SafarTimuro
 */
public class FIFOScheduler extends Scheduler {
    private final static int CLOCK_TICK = 50;
    private CopyOnWriteArrayList<ISchedulable> actors;
    private ConcurrentLinkedQueue<ArrayDeque<GameCommand>> schedules;
    private AtomicBoolean scheduling;
    private Runnable runner;
    
    public FIFOScheduler(){
        actors = new CopyOnWriteArrayList<ISchedulable>();
        schedules = new ConcurrentLinkedQueue<ArrayDeque<GameCommand>>();
        scheduling = new AtomicBoolean(false);
        runner = new Runnable() {
            public void run() {
                while(scheduling.get()){
                    createSchedule();
                    Thread.yield();
                    runSchedule();
                    try {
                        Thread.sleep(CLOCK_TICK);
                    } catch (InterruptedException exc) {
                        
                    }
                }
            }
        };
    }

    @Override
    public void addSchedulableObject(ISchedulable actor) {
        actors.add(actor);
    }

    @Override
    public boolean removeSchedulableObject(ISchedulable actor) {
        boolean success = actors.remove(actor);
        return success;
    }

    @Override
    public void startScheduler() {
        if(!scheduling.get()) {
            scheduling.getAndSet(true);
            runner.run();
        }
    }

    @Override
    public void stopScheduler(boolean forceStop) {
        scheduling.set(false);
    }
    
    public void createSchedule() {
        //Create a new queue of commands
        ArrayDeque<GameCommand> schedule = new ArrayDeque<GameCommand>(actors.size());
        for(ISchedulable actor : actors){
            schedule.add(actor.getNextAction());
        }
        //Add queue to the scheduling list
        schedules.add(schedule);
    }
    
    public void runSchedule() {
        ArrayDeque<GameCommand> schedule = schedules.poll();
        
        //Deque all the scheduled commands and run them
        while(!schedule.isEmpty()){
            schedule.pollFirst().execute();
        }
    }
}
